#include "fig_enemy_formationcraft.h"
#include "fig_functions.h"
#include "fig_bullet.h"
#include "fig_enemybullet_master.h"
#include "fighter.h"

#include "dd/dd_man.h"
#include "math/facing.h"
#include "num/rand.h"


#include "util/mmgr.h"		    // Needs to come in early
#include "util/common_macros.h"		// macros
#include "util/log.h"		    // logging
#include "util/timer.h"		    // logging


FIGEnemyFormationCraft::FIGEnemyFormationCraft(FIGEnemyCraft::ENEMY_TYPES EnemyType) : 
										FIGEnemy3DRotate(EnemyType),
										m_FormationState(STATE_FORMATION),
										m_RandomSwayDegree(0),
										m_bSwayPlus(false),
										m_LastSway(false),
										m_DelayStanding(0),
										m_ExtraOffsetY(0)
{
	m_IsReadyToFire = false;  
	m_Accel = 0;
	m_IsHitTestCircle = true;
	
}







void		FIGEnemyFormationCraft::Tick(float dt)
{
	FIGEnemy3DRotate::Tick(dt);

	if(!m_IsAlive)
		return;

	const float EXTRA_OFFSET = 0.05f;

	if(m_DelayStanding > 0)
		m_DelayStanding -= dt;
    
	m_ExtraOffsetY = 0;
	switch(m_FormationState)
	{
	case STATE_FORMATION:
	{
		m_ExtraOffsetY += (EXTRA_OFFSET * dt);
		M_GoalPos.y += m_ExtraOffsetY;
		math::Vec2 Dir = ( M_GoalPos  - (m_Pos + math::Vec2(0,m_ExtraOffsetY)) );
		if(Dir.Magnitude() > 0.01f)
		{
			Dir.Normalize();
			m_Pos += (Dir  * dt * m_Speed);

			m_Accel += dt;
			if(m_Accel > 1)
				m_Accel = 1.0f;

			if(m_Speed > 0.45f)
				m_Speed -=  ( dt * m_Accel)  ;
			
			float Degree = math::Facing::AngleVector(Dir);
			FigFunctions::ToDegree(m_Rotation, Degree + 180.0f, 0.08f);
		}
		else
		{
			NextState();				
		}
	}
	break;

	case STATE_AIMING_FRONT:
		m_ExtraOffsetY += (EXTRA_OFFSET * dt);
		FigFunctions::ToDegree(m_Rotation, 360.0f, 0.5f);
		if(m_Rotation == 360.0f || m_Rotation == 0)
			NextState();
	break;

	case STATE_DELAY_TIME:
		m_ExtraOffsetY += (EXTRA_OFFSET * dt);
		//MoveAbit(dt * 0.1f,0.5f);	  // move a little bit not to look weired standing still
		if(m_DelayStanding <= 0)
		{
			NextState();
			m_Accel = 0;
		}
	break;

	case STATE_SHOOT:

		m_IsReadyToFire = true;
            
        if(num::RAND32::Instance().RandInt(0,1) == 0)
        {
            FIGEnemyBulletMaster::Instance().Shoot(
											this,
											math::Vec2(0,0),
											FIGEnemyBulletMaster::BULLET_TYPE_CIRCLE_ROTATE,
											FIGBullet::SHOOT_STYLES_SINGLE,
											180.0f,		// degree
											0,
											false,
											NULL
          									);
        }
		//

		//if(num::RAND32::Instance().RandInt(0,1) == 0)
			m_RotateBackDegree = num::RAND32::Instance().RandFloat(  180 - 45.0f , 180 + 45.0f);
		//else
		//	m_RotateBackDegree = num::RAND32::Instance().RandFloat(  360 - 45.0f , 360.0f);


		NextState();
		break;

	case STATE_TURNINGBACK:
		m_IsReadyToFire = false;
		FigFunctions::ToDegree(m_Rotation,m_RotateBackDegree,2.0f);
		GoForward(dt);
		
		if( m_Rotation == m_RotateBackDegree )
			NextState();
		break;

	case STATE_GOBACK:

		m_Accel += dt;
		if(m_Accel > 0.5f)
			m_Accel = 0.5f;
		m_Speed += ( m_Accel  * dt);
		
		Tick_Sway(dt);
		GoForward(dt); 
		if(!IsInSideScreen())
			NextState();
		break;	   

	case STATE_DONE:
		m_IsAlive = false;
		break;

	default:
		break;

	}

	m_Pos.y += m_ExtraOffsetY;
}

void		FIGEnemyFormationCraft::NextState()
{
	m_FormationState = (FORMATION_STATE) ((int)m_FormationState + 1);
}


void		FIGEnemyFormationCraft::ReSpawn()
{	
	
	FIGEnemy3DRotate::ReSpawn();
	m_Pos = math::Vec2( num::RAND32::Instance().RandFloat(-0.1f,1.1f),- m_Sprite.m_SizeOriginal.y * 0.2f);
	m_Speed = 0.35f;
	m_RandomSwayDegree = 0;

	m_FormationState = STATE_FORMATION;
	m_bSwayPlus = false;
	m_LastSway =  false;
	m_DelayStanding = 2.0f;
	m_Accel = 0;
	m_ExtraOffsetY = 0;
	m_Rotation = 0;

	// no need this one.
	m_DelaySpawn = 0;
	
}
std::string		FIGEnemyFormationCraft::MapTypeToName(FIGEnemyFormationCraft::FORMATION_TYPE Type)
{
	switch(Type)
	{
		case FORMATION_TRIANGLE:
			return	"Formation_Triangle";
	
		case FORMATION_LINE:
			return "Formation_Line";       		
	}
    
	return "none";

}




FIGEnemyFormationCraft::FORMATION_TYPE		FIGEnemyFormationCraft::MapNameToType(const std::string& TypeName)
{
	for (unsigned int i = 0; i < FORMATION_COUNT; i++)
		if (strcmpi( MapTypeToName((FORMATION_TYPE)i).c_str(), TypeName.c_str() ) == 0)
			return (FORMATION_TYPE)i;

	return FORMATION_NONE; 

}


void	FIGEnemyFormationCraft::Tick_Sway(float dt)
{
	if(m_Rotation < 0)
		m_Rotation += 360;
	
	if(m_Rotation > 360)
		m_Rotation -= 360;
	
	if(m_RandomSwayDegree > 0 )
	{
		const float RotateSpeed = 50.0f * dt;
		m_RandomSwayDegree -= RotateSpeed;
		if(m_bSwayPlus)
			m_Rotation += RotateSpeed;
		else
			m_Rotation -= RotateSpeed;	

	}
	else
	{
		m_RandomSwayDegree = (float)num::RAND32::Instance().RandInt(45,90);
		m_bSwayPlus = !m_LastSway;
		m_LastSway = m_bSwayPlus;			
	}
}

void		FIGEnemyFormationCraft::Setup(FORMATION_TYPE Type, int Index, int MaxCount)
{
	switch(Type)
	{
		case FORMATION_LINE:
			FormLine(Index,MaxCount);
		break;
		case FORMATION_TRIANGLE:
			FormTriangle(Index,MaxCount);
		break;
	}
}

void		FIGEnemyFormationCraft::FormLine(int Index, int MaxCount)
{
	const float Gap = 1.0f / MaxCount;

	M_GoalPos = math::Vec2( Gap * Index, 0.3f);
}
	
void		FIGEnemyFormationCraft::FormTriangle(int Index, int MaxCount)
{
	int PosIndex = Index % 7;
	int Row = 1;
	

	const float MAX_TRI_ROWS = 3.0f;
	

	switch(PosIndex)
	{
		
		case 1:
		case 2:
			Row = 2;
			break;

		case 3:
		case 4:
		case 5:
		case 6:
			Row = 3;
			break;

	}

	float PosX = 0;

	switch(PosIndex)
	{
		//row 2
		case 1:
			PosX = m_Sprite.m_SizeOriginal.x * 0.5f;
			break;
		
		case 2:
			PosX = -m_Sprite.m_SizeOriginal.x * 0.5f;
			break;

		//row 3
		case 3:
			PosX = m_Sprite.m_SizeOriginal.x * 0.5f;
			break;

		case 4:
			PosX = -m_Sprite.m_SizeOriginal.x * 0.5f;
			break;

		case 5:
			PosX = m_Sprite.m_SizeOriginal.x * 1.3f;
			break;

		case 6:
			PosX = -m_Sprite.m_SizeOriginal.x * 1.3f;			
			break;

	}

	
	const float MAX_TRI_HEIGHT = 0.3f;

	M_GoalPos = math::Vec2(  PosX, 
							 -(MAX_TRI_HEIGHT/MAX_TRI_ROWS) * Row);

	M_GoalPos = math::Vec2(0.5f,0.4f) + M_GoalPos;
	

}


